package cn.javass.framework.intergration;

import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

import java.util.Map.Entry;

import cn.javass.framework.aop.annotation.IInterceptor;
import cn.javass.framework.ioc.annotation.IInject;
import cn.javass.framework.ioc.annotation.IService;
import cn.javass.framework.ioc.core.BeanDefinition;
import cn.javass.framework.ioc.core.Container;
import cn.javass.framework.orm.config.ORMConfiguration;
import cn.javass.framework.web.annotation.IAction;
import cn.javass.framework.web.annotation.IGoto;

public class IntergrationConfiguration {
	private static Map<String, IntergrationActionMapper> actionMapper = new HashMap<String, IntergrationActionMapper>();
	private static IntergrationConfiguration cfg = null;

	public static IntergrationConfiguration configure(String root) {
		if (cfg == null) {
			synchronized (IntergrationConfiguration.class) {
				cfg = new IntergrationConfiguration();
				cfg.builder(root);
				ORMConfiguration.configure(root);

			}
		}
		return cfg;
	}

	public static IntergrationConfiguration configure() {
		return configure(null);
	}

	private void builder(String rootStr) {
		if (rootStr == null) {
			rootStr = getClass().getClassLoader().getResource(".").getPath().substring(1);

		}
		File root = new File(rootStr);
		parse(root, rootStr.length());
	}

	private void parse(File root, int length) {
		if (root.isDirectory()) {
			for (File file : root.listFiles()) {
				parse(file, length);
			}
		} else {

			if (root.getName().endsWith(".class")) {

				String clazzName = root.getAbsolutePath();
				clazzName = clazzName.substring(length, clazzName.length() - 6).replace(File.separatorChar, '.');

				processAnnotation(clazzName);
			}
		}
	}

	private void processAnnotation(String clazzName) {
		try {

			Class clazz = Class.forName(clazzName);
			if (clazz.isAnnotationPresent(IService.class)) {
				makeBeanDefination(clazz);
			} else {
				if (clazz.isAnnotationPresent(IAction.class)) {
					makeActionMapper(clazz);
				}
			}
		} catch (Throwable e) {
		}
	}

	private void makeActionMapper(Class clazz) throws Exception {
		IntergrationActionMapper am = new IntergrationActionMapper();
		IAction actionAnnotation = (IAction) clazz.getAnnotation(IAction.class);
		am.setClassName(clazz.getName());
		am.setPath(actionAnnotation.path());
		makeGoto(actionAnnotation.result(), am);

		BeanDefinition bd = new BeanDefinition();
		bd.setBeanClassName(clazz.getName());
		bd.setId(am.getPath());
		bd.setSingleton(false);

		for (Field field : clazz.getDeclaredFields()) {
			if (field.isAnnotationPresent(IInject.class)) {
				IInject service = field.getAnnotation(IInject.class);
				bd.getProperties().put(field.getName(), service.id());
			}
		}
		makeBeanInterceptors(clazz, bd);
		Container.getBeanDefinitions().put(bd.getId(), bd);

		actionMapper.put(am.getPath(), am);

	}

	private void makeGoto(IGoto[] gotos, IntergrationActionMapper am) {
		for (IGoto to : gotos) {
			if ("".equals(to.key()) || "".equals(to.path())) {
				continue;
			}

			am.getGotos().put(to.key(), to.path());
		}
	}

	private void makeBeanDefination(Class clazz) throws Exception {
		BeanDefinition bd = new BeanDefinition();
		IService serviceAnnotation = (IService) clazz.getAnnotation(IService.class);
		bd.setBeanClassName(clazz.getName());
		bd.setId(serviceAnnotation.id());
		bd.setScope(serviceAnnotation.scope());
		for (Field field : clazz.getDeclaredFields()) {
			if (field.isAnnotationPresent(IInject.class)) {
				IInject service = field.getAnnotation(IInject.class);
				bd.getProperties().put(field.getName(), service.id());
			}
		}
		makeBeanInterceptors(clazz, bd);
		Container.getBeanDefinitions().put(bd.getId(), bd);
	}

	private void makeBeanInterceptors(Class clazz, BeanDefinition bd) {
		if (clazz.isAnnotationPresent(IInterceptor.class)) {
			IInterceptor iInterceptor = (IInterceptor) clazz.getAnnotation(IInterceptor.class);
			Class[] classInterceptors = iInterceptor.classes();
			putInterceptors(classInterceptors);
			bd.setClassInterceptors(Arrays.asList(classInterceptors));
		}
		for (Method method : clazz.getMethods()) {
			if (method.isAnnotationPresent(IInterceptor.class)) {
				IInterceptor iInterceptor = method.getAnnotation(IInterceptor.class);
				Class[] methodIntecerptors = iInterceptor.classes();
				putInterceptors(methodIntecerptors);
				bd.getMethodInterceptors().put(method.getName(), Arrays.asList(methodIntecerptors));
			}
		}

	}

	public static IntergrationActionMapper getActionMapper(String path) {
		return actionMapper.get(path);
	}

	private void putInterceptors(Class[] interceptors) {
		for (Class e : interceptors) {
			Container.putInterceptor(e, null);
		}
	}

	public static void main(String[] args) {
		IntergrationConfiguration.configure();
		for (Entry<String, BeanDefinition> entry : Container.getBeanDefinitions().entrySet()) {
			System.out.println(entry.getKey() + "====" + entry.getValue().getBeanClassName());
		}

	}

}
